Skip to content

Fix OpenAI streaming tool call chunk merging#6525

Closed
liushenling2001 wants to merge 2 commits into
spring-projects:mainfrom
liushenling2001:codex/fix-openai-empty-tool-calls
Closed

Fix OpenAI streaming tool call chunk merging#6525
liushenling2001 wants to merge 2 commits into
spring-projects:mainfrom
liushenling2001:codex/fix-openai-empty-tool-calls

Conversation

@liushenling2001

Copy link
Copy Markdown
Contributor

Summary

Fix OpenAI streaming tool call chunk merging for OpenAI-compatible providers.

Some OpenAI-compatible servers, observed with vLLM-backed endpoints, stream one logical tool call across multiple chunks. The tool call id, function name, and function arguments can arrive in separate chunks, and some providers repeat the same tool call id on later chunks.

The previous ChunkMerger appended every chunk that contained a tool call id as a new tool call. That could split one logical tool call into multiple incomplete tool calls. In practice this caused stream aggregation or downstream tool execution failures, including errors like:

  • NoSuchElementException / aggregation errors while converting merged chunks
  • toolName cannot be null or empty when an incomplete merged tool call reached tool execution
  • No ToolCallback found when the logical function metadata was split incorrectly across chunks

Changes

  • Merge streaming tool call chunks by tool call index or repeated id instead of appending every id-bearing chunk.
  • Preserve the first available function name.
  • Concatenate streamed function argument fragments.
  • Keep conversion strict so a final merged tool call must still contain id/function/name.
  • Add regression tests for:
    • id, function.name, and function.arguments arriving in separate chunks
    • providers repeating the same tool call id across chunks

Verification

Ran:

mvn -pl models/spring-ai-openai -Dtest=OpenAiChatModelTests test

Result: Tests run: 24, Failures: 0, Errors: 0, Skipped: 0.

OpenAI-compatible providers such as vLLM can stream a single tool call across multiple chunks, with id, function name, and function arguments arriving separately. Some providers also repeat the same tool call id on later chunks.

The previous merger appended chunks whenever an id was present, which could split one logical tool call into multiple incomplete calls. That led to stream aggregation failures and later tool execution errors such as missing or empty tool names.

Merge tool call chunks by index/id, preserve the first function name, concatenate argument fragments, and add regression coverage for split fields and repeated ids.
@ericbottard

Copy link
Copy Markdown
Member

Hi @liushenling2001,

is this a follow up to #6441 (comment)?

@jewoodev

jewoodev commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

For review context, this overlaps with #6381 in the OpenAiChatModel.ChunkMerger streaming tool-call merge path.

#6504 already covered the empty tool_calls: [] handling, while this PR and #6381 both change mergeDeltas(...) / chunkToChatCompletion(...) for split streaming tool-call deltas. It may be useful to review them together and choose one merge strategy.

@ericbottard

Copy link
Copy Markdown
Member

Hi @liushenling,

I just merged #6381 which fixes the same issue with a slightly more readable codeflow IMO.
Thanks for your analysis and PR proposal, as always

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants